using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using HslCommunication;
using HslCommunicationEx.HslNet;
using HslCommunicationEx.TypesEx;
using LambdaBuilder.Resolver;
using Newtonsoft.Json;
using Opc.Ua;
using Catastrophe.AutoSulution.EDC;
using Catastrophe.Common.AttributeEx;

namespace HslCommunicationEx.OpcUa
{
	public class OpcUaDeviceOpr : BaseNetDeviceOpr
	{
		private readonly OpcUaSiemens _opcUaSiemens;

		public OpcUaDeviceOpr(OpcUaSiemens opcUaSiemens)
		{
			this._opcUaSiemens = opcUaSiemens ?? throw new ArgumentNullException("opcUaSiemens");
		}

		public override OperateResult ReadSingle<T>(string filedName, ushort len = 0)
		{
			PropertyInfo propertyInfo = typeof(T).GetProperties().FirstOrDefault((PropertyInfo x) => x.Name.Equals(filedName));
			if (propertyInfo != null)
			{
				Tuple<OperateResult, ComDataAttribute> tuple = this.CheckReadAdr(propertyInfo);
				if (!tuple.Item1.IsSuccess)
				{
					return new OperateResult<DataValue>
					{
						IsSuccess = false,
						Message = tuple.Item1.Message
					};
				}
				ComOpcUaDataAttribute comOpcUaDataAttribute = (ComOpcUaDataAttribute)tuple.Item2;
				try
				{
					OperateResult<DataValue> operateResult = this._opcUaSiemens.ReadSingle(comOpcUaDataAttribute.Adr);
					operateResult.Content.Value = (object)base.EndiaModeForamt(operateResult.Content.Value, comOpcUaDataAttribute, propertyInfo.PropertyType, base.EndianMode);
					if (operateResult.IsSuccess)
					{
						base.CommRecord(comOpcUaDataAttribute.IsRecord, filedName, operateResult.Content.Value, OprTypeEnum.Read);
					}
					return operateResult;
				}
				catch (Exception ex)
				{
					return new OperateResult<DataValue>
					{
						IsSuccess = false,
						Message = ex.ToString()
					};
				}
			}
			return new OperateResult<DataValue>
			{
				IsSuccess = false,
				Message = "目标属性不存在"
			};
		}

		public override Tuple<T, OperateResult> ReadEntityMuti<T>(T dstT)
		{
			if (dstT == null)
			{
				throw new ArgumentNullException("dstT");
			}
			object arg = null;
			DataValue dataValue = null;
			string text = "";
			try
			{
				var list = (from x in typeof(T).GetProperties()
					select new
					{
						Property = x,
						ComOpcUaDataAb = (Attribute.GetCustomAttribute(x, typeof(ComOpcUaDataAttribute)) as ComOpcUaDataAttribute)
					} into x
					where x.ComOpcUaDataAb != null
					where !x.ComOpcUaDataAb.Ignore && !string.IsNullOrWhiteSpace(x.ComOpcUaDataAb.Adr) && x.ComOpcUaDataAb.OprType.HasFlag(OprTypeEnum.Read)
					select x).ToList();
				if (list.Count == 0)
				{
					return new Tuple<T, OperateResult>(null, new OperateResultEx
					{
						IsSuccess = false,
						Message = "未检测到可读属性"
					});
				}
				List<string> dataAdr = list.Select(x => x.ComOpcUaDataAb.Adr).ToList();
				OperateResult<List<DataValue>> operateResult = this._opcUaSiemens.ReadMulti(dataAdr);
				if (!operateResult.IsSuccess)
				{
					return new Tuple<T, OperateResult>(new T(), new OperateResultEx
					{
						Message = operateResult.Message
					});
				}
				if (operateResult.Content == null)
				{
					return new Tuple<T, OperateResult>(null, new OperateResultEx
					{
						Message = "result.Content==null"
					});
				}
				if (operateResult.Content.Count != list.Count)
				{
					return new Tuple<T, OperateResult>(null, new OperateResultEx
					{
						IsSuccess = false,
						Message = "读取返回value数量!=请求地址数量"
					});
				}
				OperateResultEx operateResultEx = new OperateResultEx
				{
					Message = ""
				};
				Dictionary<string, StatusCode> dictionary = new Dictionary<string, StatusCode>();
				for (int i = 0; i < operateResult.Content?.Count; i++)
				{
					if (operateResult.Content[i] != null)
					{
						arg = list[i].Property;
						ComOpcUaDataAttribute comOpcUaDataAttribute = (ComOpcUaDataAttribute)Attribute.GetCustomAttribute(list[i].Property, typeof(ComOpcUaDataAttribute));
						operateResult.Content[i].Value = (object)base.EndiaModeForamt(operateResult.Content[i].Value, comOpcUaDataAttribute, list[i].Property.PropertyType, base.EndianMode);
						dataValue = operateResult.Content[i];
						if (StatusCode.IsGood(operateResult.Content[i].StatusCode) && operateResult.Content != null)
						{
							object value = Convert.ChangeType(operateResult.Content[i].Value, list[i].Property.PropertyType);
							operateResultEx.IsSuccess = true;
							list[i].Property.SetValue(dstT, value);
							base.CommRecord<ComOpcUaDataAttribute>(list[i].Property, value, OprTypeEnum.Read);
						}
						else if (!dictionary.ContainsKey(comOpcUaDataAttribute.Adr) && !string.IsNullOrWhiteSpace(comOpcUaDataAttribute.Adr) && operateResult.Content != null && operateResult.Content != null)
						{
							dictionary.Add(comOpcUaDataAttribute.Adr, operateResult.Content[i].StatusCode);
						}
					}
				}
				if (dictionary.Count > 0)
				{
					operateResultEx.Tag = dictionary;
					operateResultEx.Message = JsonConvert.SerializeObject(dictionary);
				}
				return new Tuple<T, OperateResult>(dstT, operateResultEx);
			}
			catch (Exception ex)
			{
				text = text + ex?.ToString() + Environment.NewLine;
				string[] obj = new string[5]
				{
					text,
					$"属性:{arg}{Environment.NewLine}",
					null,
					null,
					null
				};
				DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(3, 2);
				defaultInterpolatedStringHandler.AppendLiteral("状态:");
				defaultInterpolatedStringHandler.AppendFormatted(dataValue?.StatusCode);
				defaultInterpolatedStringHandler.AppendFormatted(Environment.NewLine);
				obj[2] = defaultInterpolatedStringHandler.ToStringAndClear();
				defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(3, 2);
				defaultInterpolatedStringHandler.AppendLiteral("数值:");
				defaultInterpolatedStringHandler.AppendFormatted<object>(dataValue?.Value);
				defaultInterpolatedStringHandler.AppendFormatted(Environment.NewLine);
				obj[3] = defaultInterpolatedStringHandler.ToStringAndClear();
				defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(3, 2);
				defaultInterpolatedStringHandler.AppendLiteral("类型:");
				defaultInterpolatedStringHandler.AppendFormatted(dataValue?.WrappedValue.TypeInfo);
				defaultInterpolatedStringHandler.AppendFormatted(Environment.NewLine);
				obj[4] = defaultInterpolatedStringHandler.ToStringAndClear();
				text = string.Concat(obj);
			}
			return new Tuple<T, OperateResult>(null, new OperateResultEx
			{
				IsSuccess = false,
				Message = text
			});
		}

		public void SetEntityDefault<T>(T t) where T : class, new()
		{
			var list = (from x in typeof(T).GetProperties()
				select new
				{
					Property = x,
					ComDataAb = (Attribute.GetCustomAttribute(x, typeof(ComDataAttribute)) as ComDataAttribute)
				} into x
				where x.ComDataAb != null
				where !x.ComDataAb.Ignore && !string.IsNullOrWhiteSpace(x.ComDataAb.Adr) && x.ComDataAb.OprType.HasFlag(OprTypeEnum.Read)
				select x).ToList();
			T obj = new T();
			foreach (var item in list)
			{
				item.Property.SetValue(t, item.Property.GetValue(obj));
			}
		}

		public override OperateResult WriteEntitySingle<T>(string filedName, dynamic value, ushort attempTimes = 0, ushort attempInterval = 30)
		{
			return WriteEntitySingle(typeof(T), filedName, value, attempTimes, attempInterval);
		}

		public override OperateResult WriteEntitySingle(Type entityType, string filedName, dynamic value, ushort attempTimes = 0, ushort attempInterval = 30)
		{
			if ((object)entityType == null)
			{
				throw new ArgumentNullException("entityType");
			}
			PropertyInfo propertyInfo = entityType.GetProperty(filedName) ?? throw new ArgumentNullException(filedName);
			Tuple<OperateResult, ComDataAttribute> tuple = base.CheckWriteAdr(propertyInfo);
			if (!tuple.Item1.IsSuccess)
			{
				return tuple.Item1;
			}
			ComOpcUaDataAttribute comOpcUaDataAttribute = (ComOpcUaDataAttribute)tuple.Item2;
			this.GetValue(propertyInfo, comOpcUaDataAttribute, ref value);
			Type type = ((EnDeCode.GetType(comOpcUaDataAttribute.WriteDataType) == null) ? propertyInfo.PropertyType : EnDeCode.GetType(comOpcUaDataAttribute.WriteDataType));
			value = EndiaModeForamt(value, comOpcUaDataAttribute, type, base.EndianMode);
			try
			{
				dynamic val = this._opcUaSiemens.WriteSingle(comOpcUaDataAttribute.Adr, value);
				CommRecord(comOpcUaDataAttribute.IsRecord, filedName, value, OprTypeEnum.Write);
				return val;
			}
			catch (Exception ex)
			{
				return new OperateResult
				{
					IsSuccess = false,
					Message = ex.ToString()
				};
			}
		}

		public override OperateResult WriteEntityMuti<T>(T entity, Expression<Func<T, object>> exp, ushort attempTimes = 0, ushort attempInterval = 30)
		{
			List<string> columnNames = LambdaResolver.GetColumnNames(exp);
			if (columnNames.Count == 0)
			{
				throw new Exception("目标地址不存在！");
			}
			Type typeFromHandle = typeof(T);
			List<PropertyInfo> list = new List<PropertyInfo>();
			foreach (string item in columnNames)
			{
				PropertyInfo property = typeFromHandle.GetProperty(item);
				Tuple<OperateResult, ComDataAttribute> tuple = base.CheckWriteAdr(property);
				if (!tuple.Item1.IsSuccess)
				{
					return tuple.Item1;
				}
				list.Add(property);
			}
			var list2 = (from x in list
				select new
				{
					Property = x,
					ComOpcUaDataAb = (Attribute.GetCustomAttribute(x, typeof(ComOpcUaDataAttribute)) as ComOpcUaDataAttribute)
				} into x
				where x.ComOpcUaDataAb != null
				where !x.ComOpcUaDataAb.Ignore && !string.IsNullOrWhiteSpace(x.ComOpcUaDataAb.Adr) && x.ComOpcUaDataAb.OprType.HasFlag(OprTypeEnum.Write)
				select x).ToList();
			List<DataValueEntity> list3 = new List<DataValueEntity>();
			foreach (var item2 in list2)
			{
				object value = item2.Property.GetValue(entity);
				this.GetValue(item2.Property, item2.ComOpcUaDataAb, ref value);
				Type type = ((EnDeCode.GetType(item2.ComOpcUaDataAb.WriteDataType) == null) ? item2.Property.PropertyType : EnDeCode.GetType(item2.ComOpcUaDataAb.WriteDataType));
				value = EndiaModeForamt(value, item2.ComOpcUaDataAb, type, base.EndianMode);
				list3.Add(new DataValueEntity
				{
					Adr = item2.ComOpcUaDataAb.Adr,
					Value = value
				});
			}
			OperateResult operateResult = this._opcUaSiemens.WriteMuti(list3);
			if (operateResult.IsSuccess)
			{
				foreach (var item3 in list2)
				{
					dynamic value2 = item3.Property.GetValue(entity);
					CommRecord<ComOpcUaDataAttribute>(item3.Property, value2, OprTypeEnum.Write);
				}
			}
			return operateResult;
		}

		public override DataTable CreateDsSchema<T>()
		{
			return base.CreateDsSchema<T, ComOpcUaDataAttribute>();
		}
	}
}
